package io.gitee.tooleek.lock.spring.boot.core.key.strategy;

import io.gitee.tooleek.lock.spring.boot.annotation.Key;
import io.gitee.tooleek.lock.spring.boot.annotation.Lock;
import io.gitee.tooleek.lock.spring.boot.annotation.RLock;
import io.gitee.tooleek.lock.spring.boot.annotation.ZLock;
import io.gitee.tooleek.lock.spring.boot.core.key.LockKey.Builder;
import io.gitee.tooleek.lock.spring.boot.core.key.RedisLockKey;
import io.gitee.tooleek.lock.spring.boot.core.key.ZookeeperLockKey;
import io.gitee.tooleek.lock.spring.boot.enumeration.InterProcess;
import io.gitee.tooleek.lock.spring.boot.enumeration.LockScheme;
import io.gitee.tooleek.lock.spring.boot.enumeration.LockType;
import io.gitee.tooleek.lock.spring.boot.exception.KeyBuilderException;
import io.gitee.tooleek.lock.spring.boot.exception.LockValidateException;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @BelongsPackage: io.gitee.tooleek.lock.spring.boot.core.strategy
 * @Author: zsx
 * @CreateTime: 2019-04-17 10:00
 * @Description: 属性锁处理
 */
public class PropertiesKeyStrategy extends KeyStrategy {

	public PropertiesKeyStrategy(LockScheme scheme, String className, String methodName, Method realMethod,
			Object[] args) {
		super(scheme, className, methodName, realMethod, args);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Builder generateBuilder() throws KeyBuilderException {
		Builder keyBuilder;
		if(scheme==LockScheme.REDIS) {
			keyBuilder = RedisLockKey.newRedisKeyBuilder();
		}else {
			keyBuilder = ZookeeperLockKey.newZookeeperKeyBuilder();
		}

		//增加keys，用来保存所有的key，这样子让可重用锁支持多key
		List<String> keys = new ArrayList<>();

		for (int i = 0; i < args.length; i++) {
			Object obj = args[i];
			Class objectClass = obj.getClass();
			Field[] fields = objectClass.getDeclaredFields();
			for (Field field : fields) {
				if (null != field.getAnnotation(Key.class)) {
					field.setAccessible(true);
					try {
						keys.add(field.getName() + ":" + field.get(obj).toString());
					} catch (IllegalArgumentException e) {
						throw new KeyBuilderException("生成builder失败", e);
					} catch (IllegalAccessException e) {
						throw new KeyBuilderException("生成builder失败", e);
					}
				}
			}
		}

		//对keys排序
		Collections.sort(keys);

		if (realMethod.getAnnotation(Lock.class) != null) {
			Lock lock = realMethod.getAnnotation(Lock.class);
			dealWithKeyBuilder(lock.lockType(), keyBuilder, keys);
		} else if (realMethod.getAnnotation(RLock.class) != null) {
			RLock lock = realMethod.getAnnotation(RLock.class);
			dealWithKeyBuilder(lock.lockType(), keyBuilder, keys);
		} else if (realMethod.getAnnotation(ZLock.class) != null) {
			//这里我没啥用zookpeeper做过锁，所以，我只能推测zk锁的mutex等于REENTRANT锁
			ZLock lock = realMethod.getAnnotation(ZLock.class);
			if (lock.interProcess() == InterProcess.MUTEX) {
				dealWithKeyBuilder(LockType.REENTRANT, keyBuilder, keys);
			} else {
				dealWithKeyBuilder(null, keyBuilder, keys);
			}
		} else {
			throw new LockValidateException("unsupport lock type");
		}

		return keyBuilder;
	}

}
